#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <jsoncpp/json/json.h>
#include <sys/types.h>
#include <sys/socket.h>
enum
{
    OK=0,
    DIV_ZERO_ERR,
    MOD_ZERO_ERR,
    OP_ZERO_ERR,
};
#define SEP " "
#define SEP_LEN strlen(SEP)//不能使用sizeof，用sizeof会统计到'\0'
#define LINE_SEP "\r\n"
#define LINE_SEP_LINE strlen(LINE_SEP)
//"_exitcode result" -> "content_len"\r\n"_exitcode result"\r\n
//"_x _op _y" -> "content_len"\r\n"_x _op _y"\r\n
std::string enLength(const std::string& text)//text:_x _op _y。添加协议规则，用于构建一个完整的报文（类似"打包"）
{
    std::string send_string=std::to_string(text.size());//计算有效载荷的长度"_x _op _y"
    send_string+=LINE_SEP;
    send_string+=text;
    send_string+=LINE_SEP;
    return send_string;
}
//_exitcode result
bool deLength(const std::string& package,std::string* text)//获取报文中的有效载荷（类似"解包"）
{
    auto pos=package.find(LINE_SEP);
    if(pos==std::string::npos){return false;}
    int textLen=std::stoi(package.substr(0,pos));//计算有效载荷的长度
    *text=package.substr(pos+LINE_SEP_LINE,textLen);
    return true;
}
class Request//请求类
{
public:
    Request(int x,int y,char op)
        :_x(x)
        ,_y(y)
        ,_op(op)
    {}
    Request()
        :_x(0)
        ,_y(0)
        ,_op(0)
    {}
    bool serialize(std::string* out)//序列化，将成员变量转字符串
    {
#ifdef MYSELF
        //结构化->"_x _op _y"
        *out="";//清空string对象
        std::string x_tostring=std::to_string(_x);
        std::string y_tostring=std::to_string(_y);
        *out=x_tostring+SEP+_op+SEP+y_tostring;//_x _op _y
#else
        //Json序列化
        Json::Value root;//Json::Value万能对象，可接收任何对象
        root["first"]=_x;//自动将_x转换为字符串
        root["second"]=_y;
        root["oper"]=_op;
        //序列化
        Json::FastWriter writer;//Json::StyledWriter write;等价
        *out=writer.write(root);//将root进行序列化，返回值为string对象，接收即可
#endif
        return true;
    }
    bool deserialize(const std::string& in)//反序列化
    {
#ifdef MYSELF
        //"_x _op _y"->结构化
        auto leftSpace=in.find(SEP);//左边的空格
        auto rightSpace=in.rfind(SEP);//右边的空格
        if(leftSpace==std::string::npos||rightSpace==std::string::npos){return false;}
        if(leftSpace==rightSpace){return false;} 
        //子串提取
        std::string x_tostring=in.substr(0,leftSpace);
        if(rightSpace-(leftSpace+SEP_LEN)!=1){return false;}//表示操作符一定只占1位
        _op=in.substr(leftSpace+SEP_LEN,rightSpace-(leftSpace+SEP_LEN))[0];
        std::string y_tostring=in.substr(rightSpace+SEP_LEN);
        //对x，y进行转换
        _x=std::stoi(x_tostring); 
        _y=std::stoi(y_tostring);
#else
        //Json反序列化
        Json::Value root;//Json::Value万能对象，可接收任何对象
        Json::Reader reader;
        reader.parse(in,root);//第一个参数：解析哪个流；第二个参数：将解析的数据存放到对象中
        //反序列化
        _x=root["first"].asInt();//默认是字符串，转换为整型
        _y=root["second"].asInt();
        _op=root["oper"].asInt();//转换为整型，整型可以给char类型。
#endif
        return true;
    }
public:
    //_x _op _y
    int _x;//左操作数
    int _y;//右操作数
    char _op;//操作符
};

class Response//响应类
{
public:
    Response()
        :_exitCode(0)
        ,_result(0)
    {}
    Response(int exitCode,int result)
        :_exitCode(exitCode)
        ,_result(result)
    {}
    bool serialize(std::string* out)//序列化，将成员变量转string对象
    {
#ifdef MYSELF
        *out="";//清空string对象
        std::string outString=std::to_string(_exitCode)+SEP+std::to_string(_result);
        *out=outString;
#else
        //Json序列化
        Json::Value root;//Json::Value万能对象，可接收任何对象
        root["exitCode"]=_exitCode;//自动将_exitCode转换为字符串
        root["result"]=_result;
        //序列化
        Json::FastWriter writer;//Json::StyledWriter write;等价
        *out=writer.write(root);//将root进行序列化，返回值为string对象，接收即可

#endif
        return true; 
    }
    bool deserialize(const std::string& in)//反序列化
    {
#ifdef MYSELF
        auto space=in.find(SEP);//找空格
        if(space==std::string::npos){return false;}
        std::string exitString=in.substr(0,space);
        std::string resString=in.substr(space+SEP_LEN);
        if(exitString.empty()||resString.empty()){return false;}//一个字符串为空就false
        _exitCode=std::stoi(exitString);
        _result=std::stoi(resString);
#else
        //Json反序列化
        Json::Value root;//Json::Value万能对象，可接收任何对象
        Json::Reader reader;
        reader.parse(in,root);//第一个参数：解析哪个流；第二个参数：将解析的数据存放到对象中
        //反序列化
        _exitCode=root["exitCode"].asInt();//默认是字符串，转换为整型
        _result=root["result"].asInt();
#endif
        return true;
    }
public:
    int _exitCode;//0表示计算成功，非零代表除零等错误
    int _result;//运算结果
};

bool recvPackage(int sock,std::string& inbuffer,std::string* text)//服务器/客户端读取报文
{
    //将缓冲区数据拆分成一个个报文"content_len"\r\n"_x _op _y"\r\n
    char buffer[1024];
    while(1)
    {
        ssize_t n=recv(sock,buffer,sizeof(buffer)-1,0);//阻塞式读取，等价于read接口
        if(n>0)
        {
            buffer[n]=0;//字符串末尾添加'\0'
            inbuffer+=buffer;
            //拆分成一个个报文
            auto pos=inbuffer.find(LINE_SEP);//找\r\n的起始位置
            if(pos==std::string::npos)//没找到说明暂时还没找到\r\n分隔符，跳过本次循环，等待下次读取
            {
                continue;
            }
            std::string textLenString=inbuffer.substr(0,pos);
            int textLen=std::stoi(textLenString);//拿出有效载荷的长度
            int totalLen=textLenString.size()+2*LINE_SEP_LINE+textLen;//单个报文总长度
            if(inbuffer.size()<totalLen)//说明缓冲区长度还不到一个报文大小，需要跳过本次循环继续读取
            {
                continue;
            }
            std::cout<<"截取报文前inbuffer中的内容:\n"<<inbuffer<<std::endl;
            //走到这里，一定有一个完整的报文
            *text=inbuffer.substr(0,totalLen);//取出一个报文
            inbuffer.erase(0,totalLen);//删掉缓冲区中刚刚被提取走的报文数据
            std::cout<<"截取报文后inbuffer中的内容:\n"<<inbuffer<<std::endl;
            break;
        }
        else
        {
            return false;
        }
    }
    return true;
}
void recvPackageAll(int sock,std::string& inbuffer,std::vector<std::string>* out)
{
    std::string line; 
    while(recvPackage(sock,inbuffer,&line))
    {
        out->push_back(line);
    }
}